package com.heihu577.util;

import com.aliyun.oss.OSS;
import com.heihu577.bean.AliyunOSSBean;
import com.heihu577.bean.MarkdownFile;
import com.heihu577.bean.enums.FxmlResources;
import com.heihu577.bean.enums.NamingsConfig;
import com.heihu577.controller.MyAppController;
import com.heihu577.controller.child.MarkdownResultController;
import javafx.application.Platform;
import javafx.concurrent.Task;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.control.ProgressBar;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.stage.Window;

import java.io.File;
import java.io.IOException;
import java.net.URLDecoder;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Vector;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static com.heihu577.bean.AliyunOSSBean.BUCKET_NAME;
import static com.heihu577.bean.AliyunOSSBean.ENDPOINT;

public class UploadUtils {
    public static class BasicAliyunOSSTask<T> extends Task<T> {
        protected MyAppController myAppController;
        protected MarkdownFile markdownFile;
        protected OSS ossClient;
        protected AliyunOSSBean aliyunOSSBean;

        public BasicAliyunOSSTask(MyAppController myAppController, MarkdownFile markdownFile, OSS ossClient, AliyunOSSBean aliyunOSSBean) {
            this.myAppController = myAppController;
            this.markdownFile = markdownFile;
            this.ossClient = ossClient;
            this.aliyunOSSBean = aliyunOSSBean;
        }

        @Override
        protected T call() throws Exception {
            return null;
        }
    }

    public static class UploadByAliyunOSSTask extends BasicAliyunOSSTask<String> {
        private StringBuffer resultMd = new StringBuffer();
        private Window window;
        private VBox vbox;
        private ProgressBar progressBar;
        private Vector<String> ossUploadedFile = new Vector();

        public UploadByAliyunOSSTask(MarkdownFile markdownFile, MyAppController myAppController,
                                     OSS ossClient, VBox vbox, ProgressBar progressBar, Window window,
                                     AliyunOSSBean aliyunOSSBean) {
            super(myAppController, markdownFile, ossClient, aliyunOSSBean);
            this.window = window;
            this.vbox = vbox;
            this.progressBar = progressBar;
        }

        @Override
        protected void updateMessage(String message) {
            super.updateMessage(message);
        }

        @Override // 使用 updateValue, 在处理完毕后, 进行弹窗
        protected void updateValue(String value) {
            super.updateValue(value);
            try {
                this.window.setHeight(this.window.getHeight() - 16); // 处理完毕后, 缩减回原来的高度
                this.vbox.getChildren().remove(progressBar); // 处理完毕, 删除进度条
                Stage stage = new Stage();
                FXMLLoader fxmlLoader = new FXMLLoader(FxmlResources.MARKDOWN_RESULT.getUrl()); // 通过 new FXMLLoader 的方式, 可以传递作用域
                Scene scene = new Scene(fxmlLoader.load());
                MarkdownResultController markdownResultController = (MarkdownResultController) fxmlLoader.getController();
                markdownResultController.setMyAppController(myAppController); // 打印日志使用
                markdownResultController.setOssUploadedFile(ossUploadedFile); // 已经上传完毕的图片, 传递过去
                markdownResultController.setOssClient(ossClient); // 将当前的 OSS 对象传入过去, 方便删除文件用
                markdownResultController.setAliyunOSSBean(aliyunOSSBean); // 通过调用单独的 aliyunOSSBean 中的方法进行删除文件
                markdownResultController.setMarkdownFile(this.markdownFile); // 将具体的 MarkdownFile 传递过去
                stage.setTitle(NamingsConfig.MARKDOWN_RESULT_TITLE.name + "[" + markdownFile.getFile().getAbsolutePath() + "]");
                stage.setScene(scene);
                stage.setOnShown(e -> {
                    // 设置加载完毕的事件, 将处理结果放进去
                    markdownResultController.markdownContent.setText(resultMd.toString());
                    markdownResultController.setHostServices(markdownResultController.getHostServices());
                });
                stage.show();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }

        @Override
        protected String call() throws Exception {
            String parent = markdownFile.getFile().getParent(); // 得到父目录
            // Map<String, String> urls = markdownFile.getUrls(); // 得到所有图片
            List<String> urls = markdownFile.getUrls();
            // 准备替换, 匹配了两次, 这里将上次匹配到的, 作为这次的修改
            Pattern compile = Pattern.compile(MarkdownFile.IMAGE_PATTERN, Pattern.MULTILINE);
            Matcher matcher = compile.matcher(markdownFile.getContent());
            int count = 0;
            // 边 find, 边上传
            for (String filename : urls) {
                matcher.find(); // 边 find 边上传
                if (filename.equals(URLDecoder.decode(matcher.group(2)))) {
                    File file = new File(parent, filename);
                    // 图片上传, 一定要在 putObject 后进行更新进度, 否则还没等监听到, 任务就已经结束了!
                    String URL = "https://" + BUCKET_NAME + "." + ENDPOINT + "/" + filename;
                    this.updateMessage("[+] Upload " + filename + " => " + URL); // 打印日志
                    ossClient.putObject(BUCKET_NAME, filename, file);
                    count++;
                    // 可能因为 OSS 上传速度过快, 导致日志没有打印出来, 不过不影响.
                    ossUploadedFile.add(filename);
                    this.updateProgress(count, urls.size()); // 进度条信息处理
                    matcher.appendReplacement(resultMd, "![](" + URL + ")");
                }
            }
            // 将末尾追加进去
            matcher.appendTail(resultMd);
            this.updateMessage("[+] 处理完毕! 本次处理了 " + count + " 张图片!");
            return resultMd.toString();
        }
    }

    // 删除图片的任务
    public static class DeleteByAliyunOSSTask extends BasicAliyunOSSTask<Void> {
        private List<String> ossUploadedFile;

        public DeleteByAliyunOSSTask(MyAppController myAppController, MarkdownFile markdownFile, OSS ossClient, AliyunOSSBean aliyunOSSBean, List<String> ossUploadedFile) {
            super(myAppController, markdownFile, ossClient, aliyunOSSBean);
            this.ossUploadedFile = ossUploadedFile;
        }


        @Override
        protected Void call() throws Exception {
            for (String uploadedFile : ossUploadedFile) {
                String URL = "https://" + BUCKET_NAME + "." + ENDPOINT + "/" + uploadedFile;
                this.updateMessage("[-] Deleting: " + URL);
                ossClient.deleteObject(BUCKET_NAME, uploadedFile);
            }
            this.updateMessage("[+] " + markdownFile.getFile().getAbsolutePath() + " 生成的网络图片删除完毕!");
            return null;
        }
    }
}
